﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;

namespace UniSender
{
    using IExpando = IDictionary<string, object>;

    /// <summary>
    /// Построение URL и тела запроса к сервису
    /// </summary>
    public class UniSenderRequest
    {
        public const string HOST = "http://api.unisender.com";

        public string Host { get; protected set; }
        public string Lang { get; protected set; }
        public string Method { get; protected set; }
        public string Key { get; protected set; }
        public IExpando Args { get; protected set; }

        public bool TestMode { get; set; }

        public UniSenderRequest(string host, string lang, string method, string key, IExpando args)
        {
            Host = host;
            Lang = lang;
            Method = method;
            Key = key;
            Args = args;
        }

        public UniSenderRequest(string lang, string method, string key, IExpando args)
            : this(HOST, lang, method, key, args)
        { }

        public UniSenderRequest(string lang, string method, string key)
            : this(HOST, lang, method, key, null)
        { }

        protected virtual string GetUrl()
        {
            return string.Format("{0}/{1}/api/{2}", Host, Lang, Method);
        }

        protected virtual void AddParameter(StringBuilder query, string key, object value)
        {
            if (value == null) return;

            string svalue = null;
            if (value is IExpando)
            {
                foreach (var item in value as IExpando)
                    if (!string.IsNullOrEmpty(item.Key))
                        AddParameter(query, key + "[" + item.Key + "]", item.Value);
            }
            else if (value is IEmailAttachment[])
            {
                foreach (var attachment in value as IEmailAttachment[])
                    query
                        .Append("&")
                        .Append(HttpUtility.UrlEncode(key + "[" + attachment.Name + "]"))
                        .Append("=")
                        .Append(attachment.GetEncodedContent());
            }
            else
            {
                if (value is Array)
                {
                    var sarray = (value as Array).Cast<object>()
                        .Where(item => item != null)
                        .Select(item => item.ToString())
                        .ToArray();
                    if (sarray.Length > 0)
                        svalue = string.Join(",", sarray);
                }
                else
                    svalue = value.ToString();

                if (svalue != null)
                    query
                        .Append("&")
                        .Append(HttpUtility.UrlEncode(key))
                        .Append("=")
                        .Append(HttpUtility.UrlEncode(svalue));
            }
        }

        public virtual string GetQuery()
        {
            StringBuilder query = new StringBuilder("format=json&api_key=").Append(HttpUtility.UrlEncode(Key));
            if (Args != null)
                foreach (var param in Args)
                    if (!string.IsNullOrEmpty(param.Key))
                        AddParameter(query, param.Key, param.Value);
            if (TestMode && (Args == null || !Args.ContainsKey("test_mode")))
                query.Append("&test_mode=1");
            return query.ToString();
        }

        public virtual string GetUrl(bool useGet)
        {
            var url = GetUrl();
            if (useGet)
                url += "?" + GetQuery();
            return url;
        }

        public virtual string Send(bool useGet)
        {
            string url = null;
            string query = null;
            string httpMethod = useGet ? "GET" : "POST";
            try
            {
                url = GetUrl(useGet);
                query = useGet ? "" : GetQuery();
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                if (!useGet)
                {
                    byte[] data = UTF8Encoding.UTF8.GetBytes(query);
                    request.Method = httpMethod;
                    request.ContentType = "application/x-www-form-urlencoded";
                    request.ContentLength = data.Length;
                    request.GetRequestStream().Write(data, 0, data.Length);
                }
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                System.IO.StreamReader stream = new System.IO.StreamReader(response.GetResponseStream());
                return stream.ReadToEnd();
            }
            catch (Exception exc)
            {
                throw new UniSenderTransportException("Произошла ошибка при выполнении запроса к серверу", exc)
                {
                    Lang = Lang,
                    Method = Method,
                    Key = Key,
                    Args = Args,
                    HttpMethod = httpMethod,
                    Url = url,
                    Query = query
                };
            }
        }
    }
}
